#include <assert.h>
#include <ctype.h>
#include "commapi.h"
#include "commpull.h"
#include "strlist.h"
#include "base64.h"
#include "dataapi.h"
#include "protocmd.h"
#include "strutils.h"
#include "utils.h"
#include "utils2.h"
#include "pullsdk.h"


#define ERR_BUFFER_SIZE		-901
#define ERR_IO				-902

#define DATA_BUFFER_SIZE	16*1024*1024		//数据包大小
#define RT_DATA_BUFFER_SIZE	32*1024
#define ROW_DATA_LEN		32*1024			//每条记录大小
#define TABLE_STRUCTURE_DATA_LEN		4*1024

#define LOWER_STRING_I	'i'
#define UPPER_STRING_I	'I'
#define LOWER_STRING_S	's'
#define UPPER_STRING_S	'S'
#define LOWER_STRING_B	'b'
#define UPPER_STRING_B	'B'

static int plLastError=0;
#define COMM_OBJECT_MAGIC 0x636f6d6d
typedef struct {
	UDK_U32 magic;
	UDK_HANDLE commpro;
	char *buffer;
	char *bufferSize;
	char urlHeader[1024];
	int blockSize;
	int timeoutMS;
	char strAttTag[50];
	char strOpTag[50];
	TProtoBuf protoBuf;
	char proStruct[TABLE_STRUCTURE_DATA_LEN];
	int newRtlogType;
	//添加另一个成员：连接类型：UDP/ RS232/ RS485/ UDP/ HTTP/ .......
	enum {RS232 = 0, RS485, UDP, HTTP}LINK_TYPE;

}TNewCom;

typedef struct _DATAFIELD_{
	int fieldIndex;
	int fieldType;	//小写1  大写2
	char fieldChar[1]; //I,i, S, s,B,b
	char fieldName[64];	
	char fieldValue[64];
}TDataField, *PDataField;


////¶¨ÖÆ°æ±¾ZKGZTK-20140618-01
typedef struct _ACCEVENTLOG2_{
	char cardno[24];		//¿¨ºÅ
	unsigned int Pin;
	UDK_U8 verified;		//ÑéÖ¤ÀàÐÍ
	UDK_U8 doorID;	//ÃÅID	
	UDK_U8 even_type;		//ÊÂ¼þÀàÐÍ
	UDK_U8 reserved;
	unsigned int time_second;
}TACCEventLog2, *PACCEventLog2;

typedef struct _EVENTLOG_{
	unsigned int cardno;		//卡号
	unsigned int Pin;
	UDK_U8 verified;		//验证类型
	UDK_U8 doorID;	//门ID	
	UDK_U8 even_type;		//事件类型
	UDK_U8 reserved;
	unsigned int time_second;
}TEventLog, *PEventlog;

#define MAX_ACC_USERPIN_LEN			24
typedef struct _ACCEVENTLOG_{
	unsigned int cardno;		//¿¨ºÅ
	UDK_U8 pin[MAX_ACC_USERPIN_LEN];			//ÓÃ»§¹¤ºÅ
	UDK_U8 verified;		//ÑéÖ¤ÀàÐÍ
	UDK_U8 doorID;	//ÃÅID	
	UDK_U8 even_type;		//ÊÂ¼þÀàÐÍ
	UDK_U8 inoutstate; // ½ø³ö×´Ì¬   ½øÎª0£¬³öÎª1  2ÎªÆäËü
	unsigned int time_second;
}TACCEventLog, *PACCEventlog;

#define MAX_WORKCODE_LEN		24
#define MAX_USERPIN_LEN			24
typedef struct _EVENTLOGEX_{
	unsigned int cardNum;					//  ¿¨ºÅ
	UDK_U8 userPIN[MAX_USERPIN_LEN];			//ÓÃ»§¹¤ºÅ
	UDK_U8 verified;							//ÑéÖ¤ÀàÐÍ   ¼ûÉÏÃæ¶¨Òå
	UDK_U8 doorID;							//ÃÅID
	UDK_U8 eventType;							//ÊÂ¼þÀàÐÍ    ¼ûÉÏÃæ¶¨Òå
	UDK_U8 state;								// ½ø³ö×´Ì¬   ½øÎª0£¬³öÎª1  2ÎªÆäËü    //¿¼ÇÚ×´Ì¬
	unsigned int time_second;				//linux ¸ñÊ½Ê±¼ä
	UDK_U8 result;							//·µ»ØÖµ£¨Ä³Ð©ÊÂ¼þÖÐµÄ·µ»ØÖµ£©
	int length;								//Ä³Ð©ÊÂ¼þÖÐÐèÒªÓÐ³¤¶È¡£
	char workCodeNum[MAX_WORKCODE_LEN + 1];	//workcodeµÄÖµ¡£
	UDK_U8 reserve;							// ±£Áô
}TEventLogEx, *PEventlogEx;

static int commobj_is_valid(TNewCom* comm){
  if(comm&&comm->magic==COMM_OBJECT_MAGIC) return 1;
  return 0;
}
static int parseRTLog(int datalen, char *buffer, int maxBufferSize)
{
#define FREE_RESOURCE() \
	do{\
			if (freeFlag)\
			{\
				freeBuffer(rbuffer);\
				rbuffer = NULL;\
			}\
	}\
	while(0)
	const char rn[3]={'\r', '\n','\0'};
	char rowDatas[128]={0};
	int tt;
	char dt[128]={0};
	char errStr[256] = {0};
	TEventLog evtlog;
	int len=0, ret=0;
	char *pbuf=buffer;
	TBuffer *rbuffer = NULL;
	TBuffer tmpBuffer;
	static unsigned char RTDataBuffer[RT_DATA_BUFFER_SIZE];
	int freeFlag = 0;

	memset(&tmpBuffer, 0, sizeof(tmpBuffer));
	memset(RTDataBuffer, 0, sizeof(RTDataBuffer));
	if (maxBufferSize > RT_DATA_BUFFER_SIZE)
	{
		rbuffer = createRamBuffer(maxBufferSize);
		freeFlag = 1;
	}
	else
	{
		rbuffer = &tmpBuffer;
		rbuffer->buffer = RTDataBuffer;
		rbuffer->bufferSize = RT_DATA_BUFFER_SIZE;
		rbuffer->bufPtr = rbuffer->buffer;
		rbuffer->bufEnd = rbuffer->buffer + rbuffer->bufferSize;
		rbuffer->isRom = 1;
		freeFlag = 0;
	}

	if (NULL == rbuffer)
	{
		return ERR_BUFFER_NOT_ENOUGH;
	}

	if (datalen%(sizeof(TEventLog)) != 0)
	{
		FREE_RESOURCE();
		return ERR_RTLOG_ERRO;
	}
	while(datalen)
	{
		if (pbuf==NULL) break;
		memcpy(&evtlog, pbuf,sizeof(TEventLog));
		len=sprintf(rowDatas, "%s,%u,%u,%d,%d,%d,%d%s", FmtTTime(evtlog.time_second, dt), evtlog.Pin, evtlog.cardno, evtlog.doorID, evtlog.even_type, evtlog.reserved, evtlog.verified, rn);
		writeBuffer(rbuffer, rowDatas, len);
		ret++;
		datalen=datalen-sizeof(TEventLog);
		if (datalen)
		{
			pbuf = buffer + sizeof(TEventLog)*ret;//Ö§³ÖÍ¬Ê±·µ»Ø¶àÌõÊÂ¼þ¼ÇÂ¼
		}
	}

	datalen=rbuffer->bufferSize-(rbuffer->bufEnd-rbuffer->bufPtr);
	datalen = datalen > maxBufferSize ? maxBufferSize : datalen;
	memcpy(buffer, rbuffer->buffer, datalen);

	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
	
}

static int parseRTLogEx(int datalen, char *buffer, int maxBufferSize)
{
#define FREE_RESOURCE() \
	do{\
			if (freeFlag)\
			{\
				freeBuffer(rbuffer);\
				rbuffer = NULL;\
			}\
	}\
	while(0)
	const char rn[3]={'\r', '\n','\0'};
	char rowDatas[128]={0};
	int tt;
	char dt[128]={0};
	char errStr[256] = {0};
	TEventLogEx evtlog;
	int len=0, ret=0;
	char *pbuf=buffer;

	TBuffer *rbuffer = NULL;
	TBuffer tmpBuffer;
	static unsigned char RTDataBuffer[RT_DATA_BUFFER_SIZE];
	int freeFlag = 0;
	memset(&tmpBuffer, 0, sizeof(tmpBuffer));
	memset(RTDataBuffer, 0, sizeof(RTDataBuffer));
	if (maxBufferSize > RT_DATA_BUFFER_SIZE)
	{
		rbuffer = createRamBuffer(maxBufferSize);
		freeFlag = 1;
	}
	else
	{
		rbuffer = &tmpBuffer;
		rbuffer->buffer = RTDataBuffer;
		rbuffer->bufferSize = RT_DATA_BUFFER_SIZE;
		rbuffer->bufPtr = rbuffer->buffer;
		rbuffer->bufEnd = rbuffer->buffer + rbuffer->bufferSize;
		rbuffer->isRom = 1;
		freeFlag = 0;
	}
	

	if (NULL == rbuffer)
	{
		return ERR_BUFFER_NOT_ENOUGH;
	}

	if (datalen%(sizeof(TEventLogEx)) != 0)
	{
		FREE_RESOURCE();
		return ERR_RTLOG_ERRO;
	}
	UDK_LOGE("GetRTLog parseRTLog datalen=%d", datalen);

	while(datalen)
	{
		if (pbuf==NULL) break;
		memcpy(&evtlog, pbuf,sizeof(TEventLogEx));
		len=sprintf(rowDatas, "%u,%s,%d,%d,%d,%d,%s,%d,%d,%s,%d%s",  evtlog.cardNum, evtlog.userPIN, evtlog.verified, evtlog.doorID, evtlog.eventType, evtlog.state, FmtTTime(evtlog.time_second, dt), evtlog.result, evtlog.length, evtlog.workCodeNum, evtlog.reserve, rn);
		writeBuffer(rbuffer, rowDatas, len);
		ret++;
		datalen=datalen-sizeof(TEventLogEx);
		if (datalen)
		{
			pbuf = buffer + sizeof(TEventLogEx)*ret;//Ö§³ÖÍ¬Ê±·µ»Ø¶àÌõÊÂ¼þ¼ÇÂ¼
		}
	}
	UDK_LOGE("GetRTLog parseRTLog ret=%d", ret);

	datalen=rbuffer->bufferSize-(rbuffer->bufEnd-rbuffer->bufPtr);
	datalen = datalen > maxBufferSize ? maxBufferSize : datalen;
	memcpy(buffer,rbuffer->buffer, datalen);

	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
}


//¶¨ÖÆ°æ±¾ZKGZTK-20140618-01
static int parseAccessRTLog2(int datalen, char *buffer, int maxBufferSize)
{
#define FREE_RESOURCE() \
	do{\
	if (freeFlag)\
	{\
	freeBuffer(rbuffer);\
	rbuffer = NULL;\
}\
	}\
	while(0)

	const char rn[3]={'\r', '\n','\0'};
	char rowDatas[128]={0};
	int tt;
	char dt[128]={0};
	char errStr[256] = {0};
	TACCEventLog2 evtlog;
	int len=0, ret=0;
	char *pbuf=buffer;
	TBuffer *rbuffer = NULL;
	TBuffer tmpBuffer;
	static unsigned char RTDataBuffer[RT_DATA_BUFFER_SIZE];
	int freeFlag = 0;
	memset(&tmpBuffer, 0, sizeof(tmpBuffer));
	memset(RTDataBuffer, 0, sizeof(RTDataBuffer));
	if (maxBufferSize > RT_DATA_BUFFER_SIZE)
	{
		rbuffer = createRamBuffer(maxBufferSize);
		freeFlag = 1;
	}
	else
	{
		rbuffer = &tmpBuffer;
		rbuffer->buffer = RTDataBuffer;
		rbuffer->bufferSize = RT_DATA_BUFFER_SIZE;
		rbuffer->bufPtr = rbuffer->buffer;
		rbuffer->bufEnd = rbuffer->buffer + rbuffer->bufferSize;
		rbuffer->isRom = 1;
		freeFlag = 0;
	}

	if (NULL == rbuffer)
	{
		return ERR_BUFFER_NOT_ENOUGH;
	}

	if (datalen%(sizeof(TACCEventLog2)) != 0)
	{
		FREE_RESOURCE();
		return ERR_RTLOG_ERRO;
	}
	UDK_LOGE("GetRTLog parseAccessRTLog2 datalen=%d", datalen);

	while(datalen)
	{
		if (pbuf==NULL) break;
		memcpy(&evtlog, pbuf,sizeof(TACCEventLog2));
		len=sprintf(rowDatas, "%s,%u,%s,%d,%d,%d,%d%s", FmtTTime(evtlog.time_second, dt), evtlog.Pin, evtlog.cardno, evtlog.doorID, evtlog.even_type, evtlog.reserved, evtlog.verified, rn);
		writeBuffer(rbuffer, rowDatas, len);
		ret++;
		datalen=datalen-sizeof(TACCEventLog2);
		if (datalen)
		{
			pbuf = buffer + sizeof(TACCEventLog2)*ret;//Ö§³ÖÍ¬Ê±·µ»Ø¶àÌõÊÂ¼þ¼ÇÂ¼
		}
	}
	UDK_LOGE("GetRTLog parseAccessRTLog2 ret=%d", ret);

	datalen=rbuffer->bufferSize-(rbuffer->bufEnd-rbuffer->bufPtr);
	datalen = datalen > maxBufferSize ? maxBufferSize : datalen;
	memcpy(buffer, rbuffer->buffer, datalen);

	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
}

static int parseThirdRTLog(int datalen, char *buffer, int maxBufferSize)
{
#define FREE_RESOURCE() \
	do{\
			if (freeFlag)\
			{\
				freeBuffer(rbuffer);\
				rbuffer = NULL;\
			}\
	}\
	while(0)
	const char rn[3]={'\r', '\n','\0'};
	char rowDatas[128]={0};
	int tt;
	char dt[128]={0};
	char errStr[256] = {0};
	TACCEventLog evtlog;
	int len=0, ret=0;
	char *pbuf=buffer;

	TBuffer *rbuffer = NULL;
	TBuffer tmpBuffer;
	static unsigned char RTDataBuffer[RT_DATA_BUFFER_SIZE];
	int freeFlag = 0;
	memset(&tmpBuffer, 0, sizeof(tmpBuffer));
	memset(RTDataBuffer, 0, sizeof(RTDataBuffer));
	if (maxBufferSize > RT_DATA_BUFFER_SIZE)
	{
		rbuffer = createRamBuffer(maxBufferSize);
		freeFlag = 1;
	}
	else
	{
		rbuffer = &tmpBuffer;
		rbuffer->buffer = RTDataBuffer;
		rbuffer->bufferSize = RT_DATA_BUFFER_SIZE;
		rbuffer->bufPtr = rbuffer->buffer;
		rbuffer->bufEnd = rbuffer->buffer + rbuffer->bufferSize;
		rbuffer->isRom = 1;
		freeFlag = 0;
	}

	if (NULL == rbuffer)
	{
		return ERR_BUFFER_NOT_ENOUGH;
	}

	if (datalen%(sizeof(TACCEventLog)) != 0)
	{
		FREE_RESOURCE();
		return ERR_RTLOG_ERRO;
	}
	UDK_LOGE("GetRTLog parseRTLog datalen=%d\n", datalen);

	while(datalen)
	{
		if (pbuf==NULL) break;
		memcpy(&evtlog, pbuf,sizeof(TACCEventLog));
		len=sprintf(rowDatas, "%s,%s,%u,%d,%d,%d,%d%s", FmtTTime(evtlog.time_second, dt), evtlog.pin, evtlog.cardno, evtlog.doorID, evtlog.even_type, evtlog.inoutstate, evtlog.verified, rn);
		writeBuffer(rbuffer, rowDatas, len);
		ret++;
		datalen=datalen-sizeof(TACCEventLog);
		if (datalen)
		{
			pbuf = buffer + sizeof(TACCEventLog)*ret;//Ö§³ÖÍ¬Ê±·µ»Ø¶àÌõÊÂ¼þ¼ÇÂ¼
		}
	}
	UDK_LOGE("GetRTLog parseRTLog ret=%d\n", ret);

	datalen=rbuffer->bufferSize-(rbuffer->bufEnd-rbuffer->bufPtr);
	datalen = datalen > maxBufferSize ? maxBufferSize : datalen;
	memcpy(buffer,rbuffer->buffer, datalen);

	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
}
//字节流转字符串
static int BufferToProtocol(char *proStruct, char *buffer, int datalen, int buflen)
{
#define FREE_RESOURCE() \
	do{\
			freeBuffer(rbuffer);\
			slFree(strTitLst);\
			slFree(strTitle);\
			udk_free(tmpbuffer);\
			udk_free(rowBuf);\
	}\
	while(0)

	//char proStruct[LOW_DATA_LEN]={0};	//表结构
	const char rn[3]={'\r', '\n','\0'};		//回车换行
	char rowDatas[TABLE_STRUCTURE_DATA_LEN] = {0};	//字段数据
	char base64buf[ROW_DATA_LEN]={0};	//指纹面部模板数据
	char *rowBuf = NULL;			//行数据
	char *tmpbuffer = NULL;			//临时字段结构数据
	char *pbuf = NULL;
	char fdName[128]={0};
	char errStr[256]={0};
	int i, j;
	int rfc=0, steplen=0, fieldCount=0, ret=0;	//rfc数据字节流中的字段总数   fieldCount数据字节流中的有效字段总数
	long numVal=0;
	int position=0,len=0;
	int inBufferLen = datalen;	//传入的未解析的数据长度
	int bGotDataStructure = UDK_FALSE;
	PStrList strTitLst=slCreate("");	//所有表结构List
	PStrList strTitle=slCreate("");		//当前表结构
	TBuffer *rbuffer=createRamBuffer(DATA_BUFFER_SIZE);
	TDataField tdfield;
	PDataField dfields;

	rowBuf = (char*)udk_malloc(ROW_DATA_LEN);		//一条记录
	tmpbuffer=(char*)udk_malloc(ROW_DATA_LEN);			//字段结构列表
	dfields=(PDataField)tmpbuffer;

	//根据表ID返回表结构的字符串
	memset(rowDatas, 0, TABLE_STRUCTURE_DATA_LEN);
	slSetLines(strTitLst, proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		slSetText(strTitle, strTitLst->strs[i], ",");
		if (slNameAt(strTitle, 0, fdName, sizeof(fdName))>0)
		{
			char *slv=slValueAt(strTitle, 0);
			if (atoi(slv)==buffer[0])
			{
				bGotDataStructure = UDK_TRUE;
				break;
			}
		}
	}
	
	//把表结构字符串转换成内部表结构
	rfc=buffer[1];
	if(rfc <= 0)
	{
		//×Ö¶ÎÊýÐ¡ÓÚµÈÓÚ0£¬·µ»ØÊý¾ÝÒì³££¬²»ÊÇÕý³£µÄ±íÊý¾Ý
		FREE_RESOURCE();
		return ERR_DATA_FIELD_COUNT_ERROR;
	}

	for (i=0; i<rfc; i++)
	{
		int findex=buffer[2+i];
		for(j = 1; j < strTitle->count; j++)
		{
			if(slNameAt(strTitle, j, fdName, sizeof(fdName))>0)
			{
				int len=0;
				char fdData[256]={0};
				char *dval=slValueAt(strTitle, j);
				int tindex=atoi(dval+1);
				if (tindex == findex)
				{
					memset(&tdfield, 0, sizeof(TDataField));
					tdfield.fieldIndex=atoi(dval+1);
					memcpy(tdfield.fieldName, fdName, sizeof(fdName));
					tdfield.fieldChar[0]=dval[0];
					if ((dval[0] > 'a') && (dval[0] < 'z'))
					{
						tdfield.fieldType=1;
					}
					else if ((dval[0] > 'A') && (dval[0] < 'Z'))
					{
						tdfield.fieldType=2;
					}

					memcpy(tdfield.fieldValue, dval, strlen(dval));
					dfields[fieldCount]=*(&tdfield);
					fieldCount++;

					if (i == rfc-1)
						len = sprintf(fdData, "%s%s", tdfield.fieldName, rn);
					else
						len = sprintf(fdData, "%s,", tdfield.fieldName);
					writeBuffer(rbuffer, fdData, len);
					break;
				}
			}
		}
	}
	
	if(rfc != fieldCount)
	{
		//½âÎöËùµÃ±í×Ö¶Î×ÜÊýºÍÊý¾Ý±¾ÉíËùÖ¸¶¨µÄ×Ö¶Î×ÜÊý²»Ò»ÖÂ£¬Êý¾ÝÒì³£
		FREE_RESOURCE();
		return ERR_DATA_FIELD_COUNT_VARIANCE;
	}
	//解析字节流数据
	pbuf=buffer+fieldCount+2;	//表ID + 字段总数 = 2
	datalen-=(fieldCount+2);
	ret=0;
	while(datalen>0)
	{
		if (pbuf==NULL) break;
		for (i=0; i<fieldCount;i++)
		{
			position=0; len=0;
			memset(rowDatas, 0, TABLE_STRUCTURE_DATA_LEN);
			memset(rowBuf, 0, ROW_DATA_LEN);
			memset(base64buf, 0, ROW_DATA_LEN);
			switch(dfields[i].fieldChar[0])
			{
				case LOWER_STRING_I:	//i
					numVal=0;
					steplen=pbuf[0];
					if ((steplen > (datalen-1)) || (steplen < 0))
					{
						UDK_LOGE("BufferToProtocol error steplen=%d\n", steplen);
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(&numVal, pbuf+1,steplen);
					datalen -= (steplen+1);
					sprintf(rowDatas, "%lu", numVal);
					position+=steplen+1;
					break;
				case LOWER_STRING_S:	//s
					steplen=pbuf[0];
					if ((steplen > (datalen-1)) || (steplen < 0))
					{
						UDK_LOGE("BufferToProtocol error steplen=%d\n", steplen);
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(rowDatas, pbuf+1,steplen);
					datalen -= (steplen+1);
					position+=steplen+1;
					break;
				case UPPER_STRING_S:	//S
					if (datalen < 2)	//长度不够2个字节
					{
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(&steplen, pbuf, 2);
					if ((steplen > (datalen-2)) || (steplen < 0))
					{
						UDK_LOGE("BufferToProtocol error steplen=%d\n", steplen);
					
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(rowDatas, pbuf+2,steplen);
					datalen -= (steplen+2);
					position+=steplen+2;
					break;
				case LOWER_STRING_B:	//b
					steplen=pbuf[0];
					if ((steplen > (datalen-1)) || (steplen < 0))
					{
						UDK_LOGE("BufferToProtocol error steplen=%d\n", steplen);
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(base64buf, pbuf+1,steplen);
					//转换为Base64
					StringEncode(rowDatas, base64buf, steplen);
					datalen -= (steplen+1);
					position+=steplen+1;
					break;
				case UPPER_STRING_B:	//B
					if (datalen < 2)	//长度不够2个字节
					{
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(&steplen, pbuf, 2);
					if ((steplen > (datalen-2)) || (steplen < 0))
					{
						UDK_LOGE("BufferToProtocol error steplen=%d\n", steplen);
						FREE_RESOURCE();
						return ERR_DATA_ERROR;
					}
					memcpy(base64buf, pbuf+2,steplen);
					//转换为Base64
					StringEncode(rowDatas, base64buf, steplen);
					datalen -= (steplen+2);
					position+=steplen+2;
					break;
				default:
					break;
			}
			if (i==fieldCount-1)
				len=sprintf(rowBuf, "%s%s", rowDatas, rn);
			else
				len=sprintf(rowBuf, "%s,", rowDatas);
			writeBuffer(rbuffer, rowBuf, len);
			if (datalen > 0) 
			{
				pbuf=pbuf+position;
			}
			else 
			{
				break;
			}
		}
		ret++;
	}
	datalen=rbuffer->bufferSize-(rbuffer->bufEnd-rbuffer->bufPtr);
    if (datalen > buflen) {
        UDK_LOGD("\nbuffer size too small, needed %d, actural %d\n", datalen, buflen);
        FREE_RESOURCE();
        return ERR_READ_BUF_INSUFFICIENT;
    }

	memcpy(buffer,rbuffer->buffer, datalen);

	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
}


static int writebuffer(char *buffer, int buflen)
{
	int ret = 0, rl=0;
#ifdef WIN32
	HANDLE fhdl= CreateFile("C:\\dat",
						GENERIC_READ | GENERIC_WRITE,
						FILE_SHARE_READ | FILE_SHARE_WRITE,
						NULL,
						OPEN_ALWAYS,
						FILE_ATTRIBUTE_NORMAL ,
						NULL);

	if(fhdl == INVALID_HANDLE_VALUE) return 0;

	ret=WriteFile(fhdl, buffer, buflen, &rl, NULL);
	FlushFileBuffers(fhdl);
#endif

	return ret;
}



//连接到设备，连接成功后返回连接句柄
UDK_HANDLE UDK_API PullSDKConnect(const char *Parameters)
{
	char *proto = NULL;
	char *pName = NULL;
	char *pPassWd = NULL;
	char *pPort = NULL;
	char *pIpAdd = NULL;
	int len = 0, buflen=0;
	//static char buffer[2048] = {0};
	int ret=0,er=0;
	unsigned short cmd=0;
	char strTime[128] = {0};
	char strURL[512] = {0};

	//static char rowDatas[ROW_DATA_LEN] = {0};
	int sendlen=0;
	char Buffer[128] = {0};

	int tbId=0;
	char tbName[128] = {0};
	int i = 0;
	PStrList strTitLst=slCreate("");	//ËùÓÐ±í½á¹¹List
	PStrList strTitle=slCreate("");		//µ±Ç°±í½á¹¹
	TNewCom *newCom=(TNewCom*)udk_malloc(sizeof(TNewCom)); 
	PStrList params=slCreate("=");
#ifdef ZKBIOLOCK
    int isbluetooth = 0;
#endif
	if(!Parameters||!newCom) {
	  slFree(strTitLst); 
	  slFree(strTitle);
	  slFree(params);
	  if(newCom) udk_free(newCom);
	  return NULL;
	}
	memset(newCom, 0, sizeof(TNewCom));
	newCom->magic = COMM_OBJECT_MAGIC;
	initProtoBuf(&(newCom->protoBuf));
	
	slSetText(params, Parameters, ",");
	newCom->timeoutMS=slGetValueInt(params, "timeout",30000);
	proto=slGetValue(params, "protocol");
	newCom->blockSize=8*1024;
	if(proto)
	{
		PST_COMM_MODULE intf = find_comm_module_by_proto(proto);
		if(intf){
#ifdef ZKBIOLOCK
            if (strcmp(proto, "BLUETOOTH")==0) {
                isbluetooth = 1;
            }
#endif
			char* commlib = strdup(intf->comm_lib);
			newCom->commpro=COMMPULL_INIT(commlib, 
				slGetValue(params, "address")?
				slGetValue(params, "address"):slGetValue(params, "Address"),
				slGetValueInt(params, "port",0), 
				slGetValueInt(params, "speed",0),
				NULL, 
				NULL,
				slGetValue(params, "passwd"));
			newCom->blockSize=16*1024;
			udk_free(commlib);			
			
		}else if(!strcmp(proto,COMMPRO_BLUETOOTH)){
			newCom->commpro=COMMPULL_INIT(UDK_RTLIBPREFIX COMMPRO_BLUETOOTH_LIB UDK_RTLIBSUFFIX, slGetValue(params, "BTAddress"),
				0, 0, NULL, NULL, slGetValue(params, "passwd"));
			newCom->blockSize=16*1024;
		}else if(strcmp(proto,COMMPRO_RS232)==0)
		{
			newCom->commpro=COMMPULL_INIT(UDK_RTLIBPREFIX COMMPRO_RS232_LIB UDK_RTLIBSUFFIX, slGetValue(params, "port"),
				0, slGetValueInt(params, "baudrate",115200), NULL, NULL, slGetValue(params, "passwd"));
			newCom->blockSize=16*1024;
		}else if(strcmp(proto,COMMPRO_RS485)==0)
		{
			newCom->commpro=COMMPULL_INIT(UDK_RTLIBPREFIX COMMPRO_RS485_LIB UDK_RTLIBSUFFIX, slGetValue(params, "port"),
				slGetValueInt(params, "deviceid",1), slGetValueInt(params, "baudrate",115200),
				NULL, (void *)(newCom->timeoutMS), slGetValue(params, "passwd"));
			newCom->blockSize=8*1024;
		}else if(strcmp(proto,COMMPRO_UDP)==0)
		{
			newCom->commpro=COMMPULL_INIT(UDK_RTLIBPREFIX COMMPRO_UDP_LIB UDK_RTLIBSUFFIX, slGetValue(params, "ipaddress"),
				slGetValueInt(params, "port",4370), 0, NULL, NULL, slGetValue(params, "passwd"));
			newCom->blockSize=128*1024;
		}
		else if(strcmp(proto, COMMPRO_TCP)==0)
		{
			newCom->commpro=COMMPULL_INIT(UDK_RTLIBPREFIX COMMPRO_TCP_LIB UDK_RTLIBSUFFIX, slGetValue(params, "ipaddress"),
				slGetValueInt(params, "port",4370), 0, NULL, NULL, slGetValue(params, "passwd"));
			newCom->blockSize=64*1024;
		}
	}
	slFree(params);

	/* In ZKBIOLOCK, get table struct is a separate interface,
	 * So we don't need go further here
	 * */
#ifdef ZKBIOLOCK
    if (isbluetooth == 1) {
        slFree(strTitLst);
        slFree(strTitle);
        if(newCom->commpro == NULL)
        {
            freeProtoBuf(&(newCom->protoBuf));
            free(newCom);
            return NULL;
        } else {
            return newCom;
        }
    }
#endif
    

	if(newCom->commpro == NULL)
	{		
		freeProtoBuf(&(newCom->protoBuf));
		free(newCom);
		slFree(strTitLst); 
		slFree(strTitle);
		return NULL;
	}

	//获取表结构
	cmd=CMD_GET_TABLE_STRUCT;
	buflen = TABLE_STRUCTURE_DATA_LEN;
	COMMPULL_READCMDDATA(newCom->commpro , &cmd, newCom->proStruct, &buflen, 0, (newCom->timeoutMS)*30);		//数据大时时间较长，超时*10
	//UDK_LOGD( "PULLConnect....cmd =%d\n",cmd);
	
	if (cmd != CMD_ACK_OK_NEW)	//获取表结构失败返回，错误号。并断开连接, 释放内存
	{
		plLastError = ERR_GETTABLE_STRUCT;
		freeProtoBuf(&(newCom->protoBuf));
		PullSDKDisconnect(newCom);
		//udk_free(newCom);
		slFree(strTitLst); 
		slFree(strTitle);
		return NULL;
	}
	slSetLines(strTitLst, newCom->proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		slSetText(strTitle, strTitLst->strs[i], ",");
		if (slNameAt(strTitle, 0, tbName, sizeof(tbName))>0)	
		{
			if (strcasecmp(tbName, "realtimelog") == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));//»ñÈ¡±íID
				newCom->newRtlogType = 1;	 //È·¶¨»úÆ÷ÖÐ´æÔÚ±í ¡°realtimelog¡±
			}
			else if (strcasecmp(tbName, "accessrtlog") == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));//»ñÈ¡±íID
				newCom->newRtlogType = 2;	 //È·¶¨»úÆ÷ÖÐ´æÔÚ±í ¡°accessrtlog¡±
			}
			else if (strcasecmp(tbName, "accessrtlog2") == 0)	//¶¨ÖÆ°æ±¾ZKGZTK-20140618-01
			{
				tbId=atoi(slValueAt(strTitle, 0));//»ñÈ¡±íID
				newCom->newRtlogType = 3;	 //È·¶¨»úÆ÷ÖÐ´æÔÚ±í ¡°accessrtlog2¡±
			}
		}
	}

	slFree(strTitLst); 
	slFree(strTitle);
	return newCom;
}

UDK_HANDLE UDK_API Connect(const char *Parameters)
{
    return PullSDKConnect(Parameters);
}

#ifdef ZKBIOLOCK
#if 0
#define TABLE_STRUCT "user=1,UID=i1,CardNo=i2,Pin=i3,Password=s4,Group=i5,StartTime=i6,EndTime=i7,Name=s8,Privilege=i9,SuperAuthorize=i10,Mark=s11\n" \
    "userauthorize=2,Pin=i1,AuthorizeTimezoneId=i2,AuthorizeDoorId=i3\n" \
    "holiday=3,Holiday=i1,HolidayType=i2,Loop=i3\n" \
"timezone=4,TimezoneId=i1,SunTime1=i2,SunTime2=i3,SunTime3=i4,MonTime1=i5,MonTime2=i6,MonTime3=i7,TueTime1=i8,TueTime2=i9,TueTime3=i10,WedTime1=i11,WedTime2=i12,WedTime3=i13,ThuTime1=i14,ThuTime2=i15,ThuTime3=i16,FriTime1=i17,FriTime2=i18,FriTime3=i19,SatTime1=i20,SatTime2=i21,SatTime3=i22,Hol1Time1=i23,Hol1Time2=i24,Hol1Time3=i25,Hol2Time1=i26,Hol2Time2=i27,Hol2Time3=i28,Hol3Time1=i29,Hol3Time2=i30,Hol3Time3=i31\n" \
    "transaction=5,Cardno=i1,Pin=i2,Verified=i3,DoorID=i4,EventType=i5,InOutState=i6,Time_second=i7,Index=i8\n" \
    "templatev10=6,Size=i1,UID=i2,PIN=i3,FingerID=i4,Valid=i5,Template=B6,Resverd=i7,EndTag=i8\n"
#endif

int PullSDKGetTableStruct(UDK_HANDLE Handle, char *buf, int bufferLen)
{
    PStrList strTitLst=slCreate("");	//ËùÓÐ±í½á¹¹List
	PStrList strTitle=slCreate("");		//µ±Ç°±í½á¹¹
	TNewCom *newCom=(TNewCom*)Handle;
    int len = 0, buflen=0, i = 0;
	unsigned short cmd=0;
	int tbId=0;
	char tbName[128] = {0};

	if(!commobj_is_valid(newCom)) 
	{
		return -1;
	}

	//if (newCom->proStruct[0] == '\0') {
	//	strncpy(newCom->proStruct, TABLE_STRUCT, sizeof(newCom->proStruct));
	//}
    //strncpy(buf, newCom->proStruct, strlen(newCom->proStruct));
    //return 0;

#if 1
    // if newCom->proStruct is not empty, then we get tablestruct already
    //if (strlen(newCom->proStruct) != 0) {
    //    strncpy(buf, newCom->proStruct, strlen(newCom->proStruct));
    //    return 0;
    //}

    //获取表结构
	cmd=CMD_GET_TABLE_STRUCT;
	buflen = TABLE_STRUCTURE_DATA_LEN;
	COMMPULL_READCMDDATA(newCom->commpro , &cmd, newCom->proStruct, &buflen, 0, 
                            (newCom->timeoutMS));		//modify by 20151010, 修改超时:timeoutMS*30 -> timeoutMS
	//UDK_LOGD( "PULLConnect....cmd =%d\n",cmd);
	
	if (cmd != CMD_ACK_OK_NEW)	//获取表结构失败返回，错误号。并断开连接, 释放内存
	{
		plLastError = ERR_GETTABLE_STRUCT;
		//freeProtoBuf(&(newCom->protoBuf));
		//PullSDKDisconnect(newCom);
		//udk_free(newCom);
		//slFree(strTitLst); 
		//slFree(strTitle);
		 UDK_LOGE("get table struct failed\n");
		return -1;
	}
	slSetLines(strTitLst, newCom->proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		slSetText(strTitle, strTitLst->strs[i], ",");
		if (slNameAt(strTitle, 0, tbName, sizeof(tbName))>0)	
		{
			if (strcasecmp(tbName, "realtimelog") == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));//»ñÈ¡±íID
				newCom->newRtlogType = 1;	 //È·¶¨»úÆ÷ÖÐ´æÔÚ±í ¡°realtimelog¡±
			}
			else if (strcasecmp(tbName, "accessrtlog") == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));//»ñÈ¡±íID
				newCom->newRtlogType = 2;	 //È·¶¨»úÆ÷ÖÐ´æÔÚ±í ¡°accessrtlog¡±
			}
			else if (strcasecmp(tbName, "accessrtlog2") == 0)	//¶¨ÖÆ°æ±¾ZKGZTK-20140618-01
			{
				tbId=atoi(slValueAt(strTitle, 0));//»ñÈ¡±íID
				newCom->newRtlogType = 3;	 //È·¶¨»úÆ÷ÖÐ´æÔÚ±í ¡°accessrtlog2¡±
			}
		}
	}

	slFree(strTitLst); 
	slFree(strTitle);
    
    if (bufferLen < strlen(newCom->proStruct)) {
        return ERR_READ_BUF_INSUFFICIENT;
    } else {
        strncpy(buf, newCom->proStruct, bufferLen);
    }
    return 0;
#endif
}

int PullSDKSetTableStruct(UDK_HANDLE Handle, const char *tbl_buf)
{
    TNewCom *newCom=(TNewCom*)Handle;

	if (!commobj_is_valid(newCom)) 
	{
		return -1;
	}
    if (!tbl_buf || *tbl_buf == '\0') 
    {
        return -1;
    }
    strncpy(newCom->proStruct, tbl_buf, sizeof(newCom->proStruct));
    return 0;
}

#endif
//断开与设备的连接
 void UDK_API PullSDKDisconnect(UDK_HANDLE Handle)
{
	TNewCom *newCom = (TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) return;	
	if(newCom->commpro) COMMPULL_CLOSE(newCom->commpro);
	if(newCom->buffer)	udk_free(newCom->buffer);
    freeProtoBuf(&newCom->protoBuf);
	memset((void*)newCom,0,sizeof(*newCom));
	udk_free(newCom);	
}

void UDK_API Disconnect(UDK_HANDLE Handle)
{
    PullSDKDisconnect(Handle);
    return ;
}

/*
表ID 表操作选项 要获取的字段总数 字段1 ID 字段2 ID ... 字段N ID  条件字段总数 字段1 ID 字段2 ID ... 字段N ID 字段1值长度 字段1 值 字段2 值长度 ... 字段N 值  压缩标志  
1 bytes  1 byte 1 byte  1 byte  1 byte ...  1 byte  1 byte 1 byte  1 byte ...  1 byte  1或2 bytes N bytes  1或2 bytes  ...  N bytes 1 byte 
*/
//查询设备中的数据，返回数据记录条数
 int UDK_API PullSDKGetDeviceData(void *Handle,
	char *Buffer,		
	int BufferSize,		
	const char *TableName,	
	const char *FieldNames,	
	const char *Filter,
	const char *Options
	)
{
	#define FREE_RESOURCE() \
	do{\
			freeBuffer(buffer);\
			slFree(strTitLst); \
			slFree(strTitle);\
			slFree(strTitleOpt);\
	}\
	while(0)
	TBuffer *buffer=createRamBuffer(DATA_BUFFER_SIZE);	//获取数据内存buffer
	//char proStruct[LOW_DATA_LEN]={0};		//表结构
	char rowDatas[ROW_DATA_LEN] = {0};		//行数据
	char tbName[128] = {0};
	char fieldName[128]={0};
	int i,m=0, tbId=0, cc=0, rowlen=0, buflen=0, readlen=0, tbOptId=0;
	int sendlen=0, datalen=0;
	int ret=0, kk, step=0, len;
	char confirmBuf[256]={0};
	int confirmBufLen = 0;
	int SendconfirmBufLen = 0;
	int isNewRecord = 0;
	unsigned short cmd=0,rcmd=0;

	char *tmpbuffer = NULL;
	TDataField tdfield;		//每个字段描述结构
	PDataField pfields;		//一组字段结构

	//PStrList strTitLst=slCreate("");	//所有表结构List
	PStrList strTitLst=slCreate(NULL);	//所有表结构List
	PStrList strTitle=slCreate(NULL);		//当前表结构
	PStrList strTitleOpt=slCreate(NULL);		//当前表结构

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) 
	{
		FREE_RESOURCE();
		return ERROR_HANDLE;
	}

	assert(Buffer != NULL);
	if(Buffer == NULL)
	{
		FREE_RESOURCE();
		return ERROR_NO_MEM;
	}

	//获取表ID
	tbId=0;
	slSetLines(strTitLst, newCom->proStruct);
	//UDK_LOGD("Table Struct=%s\n", newCom->proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		if (0 == tbId)
		{
			slSetText(strTitle, strTitLst->strs[i], ",");
			if (slNameAt(strTitle, 0, tbName, sizeof(tbName))>0)	
			{
				if (strcasecmp(tbName, TableName) == 0)
				{
					tbId=atoi(slValueAt(strTitle, 0));//获取表ID
					//break;
				}
			}
		}
		if (0 == tbOptId)
		{
			slSetText(strTitleOpt, strTitLst->strs[i], ",");
			if (slNameAt(strTitleOpt, 0, tbName, sizeof(tbName))>0)	
			{
				if (strcasecmp(tbName, "fileopt") == 0)
				{
					tbOptId=atoi(slValueAt(strTitleOpt, 0));//获取表ID
					//break;
				}
			}
		}
		if(tbId != 0 && tbOptId != 0)
		{
			break;
		}
	}
	if (tbId==0) 
	{
		FREE_RESOURCE();
		return ERR_NOTABLE_STRUCT;	//未找到相应表结构
	}
	rowDatas[0]=tbId;	//表ID 

	//查询数据字段转换为字节流格式
	if(!strcmp(FieldNames, "*")){
		rowDatas[1]=strTitle->count-1;
		for (i=1; i<strTitle->count; i++)		
		{
			memset(fieldName, 0, sizeof(fieldName));
			if(slNameAt(strTitle, i, fieldName, sizeof(fieldName))>0)
			{
				char *val=slValueAt(strTitle, i);
				rowDatas[i+1]=atoi(val+1);
				cc++;
			}
		}
	}else{
		TStrList *dataVal=slCreate("=");
		slSetText(dataVal, FieldNames, "\t");
		cc=0;
		for(i = 0; i < dataVal->count; i++)
		{
			memset(fieldName, 0, sizeof(fieldName));
			slNameAt(dataVal, i, fieldName, sizeof(fieldName));
			if (!strlen(fieldName))
			{
				break;
			}
			else
			{
				int index=slIndexOfName(strTitle, fieldName);
				if (index>0)
				{
					char *val=slValueAt(strTitle, index);
					rowDatas[i+2]=atoi(val+1);
					cc++;
				}
				else
				{
					continue;
					//return -113;	//表结构中找不到条件字段名
				}
			}
		}
		rowDatas[1]=cc;
		slFree(dataVal);
	}

	writeBufferAuto(buffer, rowDatas, cc+2);
	
	//Options选项转换为字节流
	memset(rowDatas, 0, sizeof(rowDatas));
	if (strlen(Options) == 0){
		isNewRecord = 0;
		rowDatas[0]=0;							//data[0]   0：下载所有记录　1：下载新记录
		writeBufferAuto(buffer, rowDatas, 1);	
	}else if (strcasecmp(Options, "NewRecord") == 0){
		isNewRecord = 1;
		rowDatas[0]=1;
		rowDatas[1]=0x01;						//
		writeBufferAuto(buffer, rowDatas, 2);
	}else if(tbOptId != 0)	//无法识别的参数
	{
		int bFailed = 0;
		int nPos = 0;
		TStrList *dataVal=slCreate("=");
		slSetText(dataVal, Options, "\t");
		char szBuffer[512] = {0x0};
		if (dataVal->count > 0)
		{
			for(i = 0; i < dataVal->count; i++)
			{
				memset(fieldName, 0, sizeof(fieldName));
				slNameAt(dataVal, i, fieldName, sizeof(fieldName));
				if (!strlen(fieldName))
				{
					UDK_LOGE("GetDevice Data options Invaild FieldName\n");
					bFailed = 1;
					break;
				}
				char fdName[64]={0};
				char *dval=slValueAt(dataVal, i);
				int index=slIndexOfName(strTitleOpt, fieldName);
				UDK_LOGD("slValueAt dval=%x, slIndexOfName index=%d,fdName=%s\n", (long)dval, index, fieldName);
				if(index <= 0 || NULL == dval)
				{
					UDK_LOGE("GetDevice Data options Invaild Index or dval\n");
					bFailed = 1;
					break;
				}
				char *val=slValueAt(strTitleOpt, index);
				if(NULL == val)
				{
					UDK_LOGE("GetDevice Data options Invaild val\n");
					bFailed = 1;
					break;
				}
				int rowDatasLen=0, Slen=0;
				unsigned long vv=0; 
				memset(rowDatas, 0, sizeof(rowDatas));
				switch(val[0])
				{
					case LOWER_STRING_I:	//i
#ifdef WIN32
					vv=_atoi64(dval);
#else
					strtou32(dval, (unsigned int*)&vv);
#endif
					if ((vv & 0xFF000000) > 0)
					{
						rowDatas[0]=atoi(val+1);
						rowDatas[1]=4;
						memcpy(rowDatas+2, &vv, 4);
						rowDatasLen=6;
					}
					else if ((vv & 0xFF0000) > 0)	
					{
						rowDatas[0]=atoi(val+1);
						rowDatas[1]=3;
						memcpy(rowDatas+2, &vv, 3);
						rowDatasLen=5;
					}
					else if ((vv & 0xFF00) > 0)	
					{
						rowDatas[0]=atoi(val+1);
						rowDatas[1]=2;
						memcpy(rowDatas+2, &vv, 2);
						rowDatasLen=4;
					}
					else		
					{
						rowDatas[0]=atoi(val+1);
						rowDatas[1]=1;
						rowDatas[2]=vv;
						rowDatasLen=3;
					}
					break;
				case LOWER_STRING_S:	//s
					rowDatas[0]=atoi(val+1);
					rowDatas[1]=strlen(dval);
					memcpy(rowDatas+2, dval, strlen(dval));
					rowDatasLen=strlen(dval)+2;
					break;
				case UPPER_STRING_S:	//S
					rowDatas[0]=atoi(val+1);
					Slen=strlen(dval);
					memcpy(rowDatas+1, &Slen, 2);
					memcpy(rowDatas+3, dval, Slen);
					rowDatasLen=strlen(dval)+3;
					break;
				case LOWER_STRING_B:	//b
					break;
				case UPPER_STRING_B:	//B
					rowDatas[0]=atoi(val+1);
					Slen=strlen(dval);
					memcpy(rowDatas+1, &Slen, 2);
					memcpy(rowDatas+3, dval, Slen);
					rowDatasLen=strlen(dval)+3;
					break;
				default:
					break;
				}
				if(rowDatasLen <= 0)
				{
					UDK_LOGE("GetDevice Data options rowDatasLen < 0\n");
					bFailed = 1;
					break;
				}
				memcpy(szBuffer+nPos, rowDatas, rowDatasLen);
				nPos += rowDatasLen;
			}
		}
		else
		{
			UDK_LOGE("GetDevice Data options rowDatadataval count < 0\n");
			bFailed = 1;
		}
		
		slFree(dataVal);
		if(1 == bFailed || nPos > 255)
		{
			UDK_LOGE("GetDevice Data options failed nPos =%d\n", nPos);
			FREE_RESOURCE();		
			return ERR_INVALID_OPTIONS;
		}
		writeBufferAuto(buffer, (char*)&nPos, 1);
		writeBufferAuto(buffer, szBuffer, nPos);
	}
	else
	{
		UDK_LOGE("GetDevice Data ERR_INVALID_OPTIONS\n");
		FREE_RESOURCE();		
		return ERR_INVALID_OPTIONS;
	}
	
	//查询条件转换为字节流
	//if(strcmp(Filter, "") == 0)
	if(strlen(Filter) == 0){
		rowDatas[0]=0;	
		writeBufferAuto(buffer, rowDatas, 1);
	}else{
		TStrList *dataVal=slCreate("=");
		slSetText(dataVal, Filter, "\t");

		//获取条件字段结构
		tmpbuffer=(char*)udk_malloc(ROW_DATA_LEN);	//字段结构列表
		pfields=(PDataField)tmpbuffer;
		cc=0;

		for(i = 0; i < dataVal->count; i++)
		{
			char fdName[64]={0};
			if(slNameAt(dataVal, i, fdName, sizeof(fdName))>0)
			{
				char *dval=slValueAt(dataVal, i);
				int index=slIndexOfName(strTitle, fdName);
				if (index>0)
				{
					char *val=slValueAt(strTitle, index);
					memset(&tdfield, 0, sizeof(TDataField));
					tdfield.fieldIndex=atoi(val+1);
					memcpy(tdfield.fieldName, fdName, sizeof(fdName));
					tdfield.fieldChar[0]=val[0];
					if ((val[0] > 'a') && (val[0] < 'z'))
					{
						tdfield.fieldType=1;
					}
					else if ((val[0] > 'A') && (val[0] < 'Z'))
					{
						tdfield.fieldType=2;
					}
					memcpy(tdfield.fieldValue, dval, strlen(dval));
					pfields[cc]=*(&tdfield);
					cc++;
				}
				else
				{
					FREE_RESOURCE();
					return ERR_NOFIELD_INSTRUCT; //表结构中 条件字段不存在
				}
			}
		}
		
		memset(rowDatas, 0, sizeof(rowDatas));
		rowDatas[0]=cc;
		for (i =0; i< cc; i++)
		{
			rowDatas[i+1]=pfields[i].fieldIndex;
		}
		writeBufferAuto(buffer, rowDatas, cc+1);	//条件字段总数+字段ID
		for (i=0; i<cc; i++)
		{
			int rowDatasLen=0, Slen=0;
			unsigned long vv=0; 
			memset(rowDatas, 0, sizeof(rowDatas));
			switch(pfields[i].fieldChar[0])
			{
				case LOWER_STRING_I:	//i
#ifdef WIN32
					vv=_atoi64(pfields[i].fieldValue);
#else
					strtou32(pfields[i].fieldValue, (unsigned int*)&vv);
#endif
					if ((vv & 0xFF000000) > 0)
					{
						rowDatas[0]=4;
						memcpy(rowDatas+1, &vv, 4);
						rowDatasLen=5;
					}
					else if ((vv & 0xFF0000) > 0)	
					{
						rowDatas[0]=3;
						memcpy(rowDatas+1, &vv, 3);
						rowDatasLen=4;
					}
					else if ((vv & 0xFF00) > 0)	
					{
						rowDatas[0]=2;
						memcpy(rowDatas+1, &vv, 2);
						rowDatasLen=3;
					}
					else		
					{
						rowDatas[0]=1;
						rowDatas[1]=vv;
						rowDatasLen=2;
					}
					break;
				case LOWER_STRING_S:	//s
					rowDatas[0]=strlen(pfields[i].fieldValue);
					memcpy(rowDatas+1, pfields[i].fieldValue, strlen(pfields[i].fieldValue));
					rowDatasLen=strlen(pfields[i].fieldValue)+1;
					break;
				case UPPER_STRING_S:	//S
					Slen=strlen(pfields[i].fieldValue);
					memcpy(rowDatas, &Slen, 2);
					memcpy(rowDatas+2, pfields[i].fieldValue, Slen);
					rowDatasLen=strlen(pfields[i].fieldValue)+2;
					break;
				case LOWER_STRING_B:	//b
					break;
				case UPPER_STRING_B:	//B
					Slen=strlen(pfields[i].fieldValue);
					memcpy(rowDatas, &Slen, 2);
					memcpy(rowDatas+2, pfields[i].fieldValue, Slen);
					rowDatasLen=strlen(pfields[i].fieldValue)+2;
					break;
				default:
					break;
			}
			writeBufferAuto(buffer, rowDatas, rowDatasLen);
		}	
	}

	buflen=buffer->bufferSize-(buffer->bufEnd-buffer->bufPtr);
	memcpy(Buffer, buffer->buffer, buflen);
	sendlen=buflen;

	//UDK_LOGE("String to buffer finish\n");
	cmd=CMD_GET_DATA;
	//保存字节流数据
	writebuffer((char*)buffer->buffer, buflen);
    buflen = BufferSize;
	//UDK_LOGE("Start COMMPULL_READCMDDATA\n");

	ret = COMMPULL_READCMDDATA(newCom->commpro , &cmd, Buffer, &buflen, sendlen, (newCom->timeoutMS)*2.5);		//数据大时时间较长，超时*10
	//UDK_LOGE("End COMMPULL_READCMDDATA\n");

#ifndef ZKBIOLOCK
	if (isNewRecord)
	{
		if (cmd==CMD_ACK_OK_NEW)
			rcmd = CMD_GET_DATA_OK;	
		else
			rcmd = CMD_GET_DATA_ERROR;
		confirmBuf[0] = tbId;  //table ID;
		SendconfirmBufLen = 1;
		confirmBufLen  = sizeof(confirmBuf);
		COMMPULL_SENDCMD2(newCom->commpro, &rcmd, confirmBuf, &confirmBufLen,SendconfirmBufLen, newCom->timeoutMS, UDK_TRUE, NULL);
		//UDK_LOGE("End SENDCMD CMD_GET_DATA_OK");
	}
#endif
	FREE_RESOURCE();
	
	if (cmd != CMD_ACK_OK_NEW)
	{
		return ret;
	}
	//以下反解析
	if(ret>=0)
	{
		//UDK_LOGE("Start BufferToProtocol");
		ret = BufferToProtocol(newCom->proStruct, Buffer, buflen, BufferSize);	//返回记录条数
		//UDK_LOGE("End BufferToProtocol");
	}

	return ret;	
	
#undef FREE_RESOURCE
}

 int UDK_API GetDeviceData(void *Handle,
	char *Buffer,		
	int BufferSize,		
	const char *TableName,	
	const char *FieldNames,	
	const char *Filter,
	const char *Options
	)
{
    return PullSDKGetDeviceData(Handle, Buffer, BufferSize, TableName, 
                            FieldNames, Filter, Options);
}

/*
	-100;	//未找到相应表结构
	-101;	//实际数据字段数大于数据结构定义字段数
	-102;	//每条记录的字段总数不一致
	-103	记录中字段排序不一致
	-6: 连接名柄错误
*/
/*
表ID 字段总数 字段1 ID 字段2 ID ... 字段N ID 字段1值长度 字段1 值 字段2 值长度 ... 字段N 值  压缩标志  
1 bytes  1 byte 1 byte  1 byte ...  1 byte  1或2 bytes N bytes  1或2 bytes  ...  N bytes 1 byte  
*/
//增加数据到设备中,返回设备成功新增的数据记录数
 int UDK_API PullSDKSetDeviceData(UDK_HANDLE Handle,
	const char *TableName,	//数据表名
	const char *Datas,		/*数据记录表示，数据是文本格式的，可以多条记录之间用\r\n分隔，各个“字段=值”对之间用逗号分隔。
						例如：
						PIN=12345,Name=Richard,Password=2298
						PIN=12346,Name=王玲玲,Password=2,Gender=Female
						PIN=1
						如果一条新数据的某些字段没有指定值，则固件会根据具体的字段定义使用默认值；
						*/
	const char *Options	/*
						扩展属性
						*/
)
{
#define FREE_RESOURCE() \
	do{\
			freeBuffer(buffer);\
			slFree(strLst); \
			slFree(strRow);\
			slFree(strTitLst); \
			slFree(strTitle);\
            free(tmpbuffer); \
	}\
	while(0)

	//char proStruct[LOW_DATA_LEN]={0};		//表结构
	char tbName[128] = {0};
	char rowDatas[ROW_DATA_LEN] = {0};
	int rowDatasLen=0, datalen=0, sendlen=0;
	unsigned short cmd;
	int ret = 0;
	int i, j;
	int tbId=0, rc=0, tbindex=0, cc=0;
	
	char *tmpbuffer = NULL;
	TDataField tdfield;
	PDataField pfields;
    
	TBuffer *buffer=createRamBuffer(DATA_BUFFER_SIZE);
	PStrList strLst=slCreate("");		//数据list
	PStrList strRow=slCreate("");		//单条记录list
	PStrList strTitLst=slCreate("");	//所有表结构List
	PStrList strTitle=slCreate("");		//当前表结构

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) 
	{
		FREE_RESOURCE();
		return ERROR_HANDLE;
	}

	//获取表结构id
	slSetLines(strTitLst, newCom->proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		slSetText(strTitle, strTitLst->strs[i], ",");
		if (slNameAt(strTitle, 0, tbName, sizeof(tbName))>0)	//获取表名
		{
			if (strcasecmp(tbName, TableName) == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));
				tbindex=i;
				break;
			}
		}
	}
	if (tbId==0) 
	{
		FREE_RESOURCE();
		return ERR_NOTABLE_STRUCT;	//未找到相应表id
	}
	rowDatas[0]=tbId;	

	//根据第一条记录确定字段
	slSetLines(strLst, Datas);
	slSetText(strRow, strLst->strs[0], "\t");	//根据第一条记录得字段长度，及字段id
	rc=strRow->count;	

	tmpbuffer=(char*)udk_malloc(ROW_DATA_LEN);	//字段结构列表
	pfields=(PDataField)tmpbuffer;
	cc=0;
	//生成表结构字节流
	for (i=0; i<strRow->count; i++)		//字段数以第一条记录的有效字段数为基准
	{
		char fieldName[64]={0};
		if(slNameAt(strRow, i, fieldName, sizeof(fieldName))>0)
		{
			int index=slIndexOfName(strTitle, fieldName);
			if (index>0)
			{
				char *val=slValueAt(strTitle, index);
				rowDatas[i+2]=atoi(val+1);

				memset(&tdfield, 0, sizeof(TDataField));
				tdfield.fieldIndex=atoi(val+1);
				memcpy(tdfield.fieldName, fieldName, sizeof(fieldName));
				tdfield.fieldChar[0]=val[0];
				if ((val[0] > 'a') && (val[0] < 'z'))
				{
					tdfield.fieldType=1;
				}
				else if ((val[0] > 'A') && (val[0] < 'Z'))
				{
					tdfield.fieldType=2;
				}
				memcpy(tdfield.fieldValue, val, strlen(val));
				pfields[cc]=*(&tdfield);
				cc++;
			}
			else 
			{
				FREE_RESOURCE();
				return ERR_NOFIELD_INSTRUCT;		//数据字段  不在数据结构定义的字段中
			}
		}
	}
	rowDatas[1]=cc;
	writeBufferAuto(buffer, rowDatas, cc+2);
	//MessageBox(NULL, Datas, "", MB_OK);

	for(i=0; i<strLst->count; i++)
	{
		memset(rowDatas, 0, sizeof(rowDatas));
		rowDatasLen=0;
		slSetText(strRow, strLst->strs[i], "\t");

		for(j=0; j<strRow->count; j++)
		{
			char fieldName[64]={0};
			if(slNameAt(strRow, j, fieldName, sizeof(fieldName))>0)
			{
				char *value=slValueAt(strRow, j);	//取字段的值
				int biglen=0;
				unsigned long vv=0;
				if (strRow->count != rc)	
				{
					FREE_RESOURCE();
					return ERR_FIELD_DIFFER;	//字段总数不一致
				}

				if (strcasecmp(pfields[j].fieldName, fieldName) != 0)
				{
					FREE_RESOURCE();
					return ERR_FIELDORDER_DIFFER;	//字段排序不一致
				}

				switch(pfields[j].fieldChar[0])
				{
					case LOWER_STRING_I:	//'i'
#ifdef WIN32
						vv=_atoi64(value);
#else
						strtou32(value, (unsigned int*)&vv);
#endif
						if (vv == 0)	//无数据
						{
							rowDatas[rowDatasLen]=0;
							rowDatasLen+=1;
						}
						else if ((vv & 0xFF000000) > 0)	
						{
							rowDatas[rowDatasLen]=4;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 4);
							rowDatasLen+=4;
						}
						else if ((vv & 0xFF0000) > 0)
						{
							rowDatas[rowDatasLen]=3;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 3);
							rowDatasLen+=3;
						}
						else if ((vv & 0xFF00) > 0)	
						{
							rowDatas[rowDatasLen]=2;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 2);
							rowDatasLen+=2;
						}
						else		
						{
							rowDatas[rowDatasLen]=1;
							rowDatasLen+=1;
							rowDatas[rowDatasLen]=vv;
							rowDatasLen+=1;
						}
						break;
					case LOWER_STRING_S:	//'s'
						rowDatas[rowDatasLen]=strlen(value);
						rowDatasLen+=1;
						memcpy(rowDatas+rowDatasLen, value, strlen(value));
						rowDatasLen=rowDatasLen+strlen(value);
						break;
					case UPPER_STRING_S:	//'S'
						biglen=strlen(value);
						memcpy(rowDatas+rowDatasLen, &biglen, 2);
						rowDatasLen+=2;
						memcpy(rowDatas+rowDatasLen, value, strlen(value));
						rowDatasLen=rowDatasLen+strlen(value);
						break;
					case LOWER_STRING_B:	//'b'
						{
							int baselen;
							char base64buf[ROW_DATA_LEN]={0};
							memcpy(base64buf, value, strlen(value));
							baselen=StringDecode(rowDatas+rowDatasLen+1,base64buf);
							rowDatas[rowDatasLen]=baselen;
							rowDatasLen+=baselen+1;
							break;
						}
					case UPPER_STRING_B:	//'B'
						{
							int baselen;
							char base64buf[ROW_DATA_LEN]={0};
							memcpy(base64buf, value, strlen(value));
							baselen=StringDecode(rowDatas+rowDatasLen+2,base64buf);
							memcpy(rowDatas+rowDatasLen, &baselen, 2);
							rowDatasLen+=baselen+2;
							break;
						}
					default:
						break;
				}
			}
		}
		if (rowDatasLen>0)
			writeBufferAuto(buffer, rowDatas, rowDatasLen);
	}
	datalen=buffer->bufferSize-(buffer->bufEnd-buffer->bufPtr);
	sendlen=datalen;
	if (datalen > DATA_BUFFER_SIZE)		//数据流大于4M
	{
		FREE_RESOURCE();
		return ERR_BUFFER_OVER;
	}

	//保存字节流数据
	writebuffer((char*)buffer->buffer, datalen);
	cmd=CMD_SET_DATA_NEW;
	ret = COMMPULL_SENDCMDDATA(newCom->commpro , &cmd, rowDatas, &datalen, (char*)buffer->buffer, sendlen, newCom->timeoutMS);
	
	FREE_RESOURCE();

	return ret;

#undef FREE_RESOURCE
	
}

int UDK_API SetDeviceData(UDK_HANDLE Handle,
	const char *TableName,
	const char *Datas,		
	const char *Options	
)
{
    return PullSDKSetDeviceData(Handle, TableName, Datas, Options);
}


 int UDK_API PullSDKGetRTLog(UDK_HANDLE Handle, char *Buffer, int BufferSize)
{
	int ret = 0;
	int buflen = 0;
	unsigned short cmd;
	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) 
	{
		ret = PullSDKLastError();
		return ret;
	}

	cmd=CMD_GET_REALTIME_LOG;
	ret = 0;
	memset(Buffer,0,BufferSize);
	buflen = BufferSize;
    UDK_LOGD("timeout: %d\n", newCom->timeoutMS);
	ret = COMMPULL_READCMDDATA(newCom->commpro, &cmd, Buffer, &buflen, 0, newCom->timeoutMS);
	if((ret>=0) && (cmd == CMD_ACK_OK_NEW))
	{
		if (newCom->newRtlogType == 3)	//¶¨ÖÆ°æ±¾ZKGZTK-20140618-01
		{
			return parseAccessRTLog2(buflen, Buffer, BufferSize);
		}
		else if(newCom->newRtlogType == 2)
		{
			ret = parseThirdRTLog(buflen, Buffer, BufferSize);
		}
		else if(newCom->newRtlogType == 1)
		{
			ret = parseRTLogEx(buflen, Buffer, BufferSize);
		}
		else
		{
			ret = parseRTLog(buflen, Buffer, BufferSize);
		}
	}
	return ret;
}

int UDK_API GetRTLog(UDK_HANDLE Handle, char *Buffer, int BufferSize)
{
    return PullSDKGetRTLog(Handle, Buffer, BufferSize);
}


//查询设备中的数据记录数，返回指定数据的记录数
 int UDK_API PullSDKGetDeviceDataCount(UDK_HANDLE Handle,
	const char *TableName,//数据表名
	const char *Filter,	//返回数据的条件，其含义同 DataQuery 函数
	const char *Options	/* 进行查询的选项。这些选项是 以逗号分隔的 项=值 对, 可能的值有：
					IgnoreCase	条件数据是否忽略大小写
					*/
)
{
#define FREE_RESOURCE() \
	do{\
			freeBuffer(buffer);\
			slFree(strLst); \
			slFree(strRow);\
			slFree(strTitLst); \
			slFree(strTitle);\
            free(tmpbuffer); \
	}\
	while(0)

	char tbName[128] = {0};
	char rowDatas[ROW_DATA_LEN] = {0};
	int sendlen=0, tbId, i;
	int ret = 0;
    int rc = 0;
    int cc = 0;
    int j = 0;
    int rowDatasLen = 0;
    int buflen = 0;
    int datalen = 0;
	unsigned short cmd;
    char *tmpbuffer = NULL;

    TDataField tdfield;
    PDataField pfields;
    
	TBuffer *buffer=createRamBuffer(DATA_BUFFER_SIZE);
	PStrList strLst=slCreate("");	//数据list
	PStrList strRow=slCreate("");	//单条记录list
	PStrList strTitLst=slCreate("");	//所有表结构List
	PStrList strTitle=slCreate("");		//当前表结构

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) {
		FREE_RESOURCE();
		return ERROR_HANDLE;
    }

	slSetLines(strTitLst, newCom->proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		slSetText(strTitle, strTitLst->strs[i], ",");
		if (slNameAt(strTitle, 0, tbName, sizeof(tbName))>0)	//获取表名
		{
			if (strcasecmp(tbName, TableName) == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));
				break;
			}
		}
	}
	if (tbId==0) 
	{
		FREE_RESOURCE();
		return ERR_NOTABLE_STRUCT;	//未找到相应表结构
	}
	rowDatas[0]=tbId;	

	//根据第一条记录确定字段
	slSetLines(strLst, Filter);
	slSetText(strRow, strLst->strs[0], "\t");	//根据第一条记录得字段长度，及字段id
	rc=strRow->count;	

	tmpbuffer=(char *)malloc(ROW_DATA_LEN);	//字段结构列表
	pfields=(PDataField)tmpbuffer;
	cc=0;
	//生成表结构字节流
	for (i=0; i<strRow->count; i++)		//字段数以第一条记录的有效字段数为基准
	{
		char fieldName[64]={0};
		if(slNameAt(strRow, i, fieldName, sizeof(fieldName))>0)
		{
			int index=slIndexOfName(strTitle, fieldName);
			if (index>0)
			{
				char *val=slValueAt(strTitle, index);
				rowDatas[i+2]=atoi(val+1);

				memset(&tdfield, 0, sizeof(TDataField));
				tdfield.fieldIndex=atoi(val+1);
				memcpy(tdfield.fieldName, fieldName, sizeof(fieldName));
				tdfield.fieldChar[0]=val[0];
				if ((val[0] > 'a') && (val[0] < 'z'))
				{
					tdfield.fieldType=1;
				}
				else if ((val[0] > 'A') && (val[0] < 'Z'))
				{
					tdfield.fieldType=2;
				}
				memcpy(tdfield.fieldValue, val, strlen(val));
				pfields[cc]=*(&tdfield);
				cc++;
			}
			else
			{
				FREE_RESOURCE();
				return ERR_NOFIELD_INSTRUCT;		//数据字段  不在数据结构定义的字段中
			}
		}
	}
	rowDatas[1]=cc;
	writeBufferAuto(buffer, rowDatas, cc+2);
	//MessageBox(NULL, Datas, "", MB_OK);

	for(i=0; i<strLst->count; i++)
	{
		memset(rowDatas, 0, sizeof(rowDatas));
		rowDatasLen=0;
		slSetText(strRow, strLst->strs[i], "\t");

		for(j=0; j<strRow->count; j++)
		{
			char fieldName[64]={0};
			if(slNameAt(strRow, j, fieldName, sizeof(fieldName))>0)
			{
				char *value=slValueAt(strRow, j);	//取字段的值
				int biglen=0;
				unsigned long vv=0;
				if (strRow->count != rc)	
				{
					FREE_RESOURCE();
					return ERR_FIELD_DIFFER;	//字段总数不一致
				}

				if (strcasecmp(pfields[j].fieldName, fieldName) != 0)
				{
					FREE_RESOURCE();
					return ERR_FIELDORDER_DIFFER;	//字段排序不一致
				}

				switch(pfields[j].fieldChar[0])
				{
					case LOWER_STRING_I:	//'i'
#ifdef WIN32
						vv=_atoi64(value);
#else
                        strtou32(value, (unsigned int *)&vv);
#endif
						if (vv == 0)	//无数据
						{
							rowDatas[rowDatasLen]=0;
							rowDatasLen+=1;
						}
						else if ((vv & 0xFF000000) > 0)	
						{
							rowDatas[rowDatasLen]=4;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 4);
							rowDatasLen+=4;
						}
						else if ((vv & 0xFF0000) > 0)
						{
							rowDatas[rowDatasLen]=3;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 3);
							rowDatasLen+=3;
						}
						else if ((vv & 0xFF00) > 0)	
						{
							rowDatas[rowDatasLen]=2;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 2);
							rowDatasLen+=2;
						}
						else		
						{
							rowDatas[rowDatasLen]=1;
							rowDatasLen+=1;
							rowDatas[rowDatasLen]=vv;
							rowDatasLen+=1;
						}
						break;
					case LOWER_STRING_S:	//'s'
						rowDatas[rowDatasLen]=strlen(value);
						rowDatasLen+=1;
						memcpy(rowDatas+rowDatasLen, value, strlen(value));
						rowDatasLen=rowDatasLen+strlen(value);
						break;
					case UPPER_STRING_S:	//'S'
						biglen=strlen(value);
						memcpy(rowDatas+rowDatasLen, &biglen, 2);
						rowDatasLen+=2;
						memcpy(rowDatas+rowDatasLen, value, strlen(value));
						rowDatasLen=rowDatasLen+strlen(value);
						break;
					case LOWER_STRING_B:	//'b'
						{
							int baselen;
							char base64buf[ROW_DATA_LEN]={0};
							memcpy(base64buf, value, strlen(value));
							baselen=StringDecode(rowDatas+rowDatasLen+1,base64buf);
							rowDatas[rowDatasLen]=baselen;
							rowDatasLen+=baselen+1;
							break;
						}
					case UPPER_STRING_B:	//'B'
						{
							int baselen;
							char base64buf[ROW_DATA_LEN]={0};
							memcpy(base64buf, value, strlen(value));
							baselen=StringDecode(rowDatas+rowDatasLen+2,base64buf);
							memcpy(rowDatas+rowDatasLen, &baselen, 2);
							rowDatasLen+=baselen+2;
							break;
						}
					default:
						break;
				}
			}
		}
		if (rowDatasLen>0)
			writeBufferAuto(buffer, rowDatas, rowDatasLen);
	}
	datalen = buffer->bufferSize-(buffer->bufEnd-buffer->bufPtr);
	sendlen=datalen;
	if (datalen > DATA_BUFFER_SIZE)		//数据流大于4M
	{
		FREE_RESOURCE();
		return ERR_BUFFER_OVER;
	}

	//保存字节流数据
	writebuffer((char *)buffer->buffer, datalen);
	cmd=CMD_GET_DATA_COUNT;
	buflen = sizeof(rowDatas); // XXX actually buflen is not size of buffer
	ret = COMMPULL_SENDCMDDATA(newCom->commpro, &cmd, rowDatas, &buflen, (char *)buffer->buffer, sendlen, newCom->timeoutMS);
	if (ret>=0 && cmd == CMD_ACK_OK_NEW)
		memcpy(&ret, buffer->buffer, 4);
    FREE_RESOURCE();
	return ret;

#undef FREE_RESOURCE
	
}

int UDK_API GetDeviceDataCount(UDK_HANDLE Handle,
	const char *TableName,
	const char *Filter,
	const char *Options	
)
{
    return PullSDKGetDeviceDataCount(Handle, TableName, Filter, Options);
}


//设备控制
 int UDK_API PullSDKControlDevice(void *Handle,
	UDK_LONG OperationID,	//执行的动作
    UDK_LONG Param1,	
	UDK_LONG Param2,	//控制,地址 1234
	UDK_LONG Param3,		//控制参数  0常闭255常开 1-254开时间(秒)
	UDK_LONG param4,
	const char *Options
)
{
	char rowDatas[256] = {0};
	int buflen=0, ret=0, sendLen = 5;
	unsigned short cmd;

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) return ERROR_HANDLE;
	
	cmd=CMD_CONTROL_DEVICE;
	rowDatas[0]=OperationID;
	rowDatas[1]=Param1;
	rowDatas[2]=Param2;
	rowDatas[3]=Param3;
	rowDatas[4]=param4;
	// add by 20150915,增加对Options参数处理
	if((Options != NULL) && (strcmp(Options, "") != 0))
	{
		memcpy(rowDatas + sendLen, Options, strlen(Options));
		sendLen += strlen(Options);	// 发送的数据长度
	}
	buflen = sizeof(rowDatas);
	ret = COMMPULL_SENDCMD2(newCom->commpro, &cmd, rowDatas, &buflen, sendLen, newCom->timeoutMS, UDK_FALSE, NULL);

	return ret;
}

int UDK_API ControlDevice(void *Handle,
	UDK_LONG OperationID,
    UDK_LONG Param1,	
	UDK_LONG Param2,
	UDK_LONG Param3,
	UDK_LONG Param4,
	const char *Options
)
{
    return PullSDKControlDevice(Handle, OperationID, Param1, Param2, 
                                        Param3, Param4, Options);
}


//删除设备中的数据
 int UDK_API PullSDKDeleteDeviceData(UDK_HANDLE Handle,
	const char *TableName,	//要删除数据所在的数据表名
	const char *Datas,		//要删除数据的条件，其含义同 DataQuery 函数
	const char *Options	/* 进行查询的选项。这些选项是 以逗号分隔的 项=值 对, 可能的值有：
					IgnoreCase	条件数据是否忽略大小写*/
	)
{
#define FREE_RESOURCE() \
	do{\
			freeBuffer(buffer);\
			slFree(strLst); \
			slFree(strRow);\
			slFree(strTitLst); \
			slFree(strTitle);\
            free(tmpbuffer); \
	}\
	while(0)

	//char proStruct[LOW_DATA_LEN]={0};	//表结构
	int i, j;
	int tbId=0, rc=0, tbindex=0, cc=0;
	char tbName[128] = {0};
	char rowDatas[ROW_DATA_LEN] = {0};
	int rowDatasLen=0, datalen;
	int sendlen;
	unsigned short cmd;
	int ret = 0;
	
	char *tmpbuffer = NULL;
	TDataField tdfield;
	PDataField pfields;
    
	TBuffer *buffer=createRamBuffer(DATA_BUFFER_SIZE);
	PStrList strLst=slCreate("");	//数据list
	PStrList strRow=slCreate("");	//单条记录list
	PStrList strTitLst=slCreate("");	//所有表结构List
	PStrList strTitle=slCreate("");		//当前表结构

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) 
	{
		FREE_RESOURCE();
		return ERROR_HANDLE;
	}

	//获取表结构
	slSetLines(strTitLst, newCom->proStruct);
	for (i=0; i<strTitLst->count; i++)
	{
		slSetText(strTitle, strTitLst->strs[i], ",");
		if (slNameAt(strTitle, 0, tbName, sizeof(tbName))>0)	//获取表名
		{
			if (strcasecmp(tbName, TableName) == 0)
			{
				tbId=atoi(slValueAt(strTitle, 0));
				tbindex=i;
				break;
			}
		}
	}
	if (tbId==0) 
	{
		FREE_RESOURCE();
		return ERR_NOTABLE_STRUCT;	//未找到相应表结构
	}
	rowDatas[0]=tbId;	

	slSetLines(strLst, Datas);
	slSetText(strRow, strLst->strs[0], "\t");	//根据第一条记录得字段长度，及字段id
	rc=strRow->count;	

	tmpbuffer=(char*)udk_malloc(ROW_DATA_LEN);	//字段结构列表
	pfields=(PDataField)tmpbuffer;
	cc=0;

	for (i=0; i<strRow->count; i++)		//字段数以第一条记录的有效字段数为基准
	{
		char fieldName[64]={0};
		if(slNameAt(strRow, i, fieldName, sizeof(fieldName))>0)
		{
			int index=slIndexOfName(strTitle, fieldName);
			if (index>0)
			{
				char *val=slValueAt(strTitle, index);
				rowDatas[i+2]=atoi(val+1);

				memset(&tdfield, 0, sizeof(TDataField));
				tdfield.fieldIndex=atoi(val+1);
				memcpy(tdfield.fieldName, fieldName, sizeof(fieldName));
				tdfield.fieldChar[0]=val[0];
				if ((val[0] > 'a') && (val[0] < 'z'))
				{
					tdfield.fieldType=1;
				}
				else if ((val[0] > 'A') && (val[0] < 'Z'))
				{
					tdfield.fieldType=2;
				}
				memcpy(tdfield.fieldValue, val, strlen(val));
				pfields[cc]=*(&tdfield);
				cc++;
			}
			else 
			{
				FREE_RESOURCE();
				return ERR_NOFIELD_INSTRUCT;		//数据字段  不在数据结构定义的字段中
			}
		}
	}
	rowDatas[1]=cc;
	writeBufferAuto(buffer, rowDatas, cc+2);

	for(i=0; i<strLst->count; i++)
	{
		memset(rowDatas, 0, sizeof(rowDatas));
		rowDatasLen=0;
		slSetText(strRow, strLst->strs[i], "\t");

		for(j=0; j<strRow->count; j++)
		{
			char fieldName[64]={0};
			if(slNameAt(strRow, j, fieldName, sizeof(fieldName))>0)
			{
				char *value=slValueAt(strRow, j);
				unsigned long vv=0, biglen=0;
				if (strRow->count != rc)	
				{
					FREE_RESOURCE();
					return ERR_FIELD_DIFFER;	//字段总数不一致
				}

				if (strcasecmp(pfields[j].fieldName, fieldName) != 0)
				{
					FREE_RESOURCE();
					return ERR_FIELDORDER_DIFFER;	//字段排序不一致
				}

				switch(pfields[j].fieldChar[0])
				{
					case LOWER_STRING_I:	//'i'
#ifdef WIN32
						vv=_atoi64(value);
#else
						strtou32(value, (unsigned int* )&vv);
#endif
						if (vv == 0)	//无数据
						{
							rowDatas[rowDatasLen]=0;
							rowDatasLen+=1;
						}
						else if ((vv & 0xFF000000) > 0)	
						{
							rowDatas[rowDatasLen]=4;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 4);
							rowDatasLen+=4;
						}
						else if ((vv & 0xFF0000) > 0)
						{
							rowDatas[rowDatasLen]=3;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 3);
							rowDatasLen+=3;
						}
						else if ((vv & 0xFF00) > 0)	
						{
							rowDatas[rowDatasLen]=2;
							rowDatasLen+=1;
							memcpy(rowDatas+rowDatasLen, &vv, 2);
							rowDatasLen+=2;
						}
						else		
						{
							rowDatas[rowDatasLen]=1;
							rowDatasLen+=1;
							rowDatas[rowDatasLen]=vv;
							rowDatasLen+=1;
						}
						break;
					case LOWER_STRING_S:	//'s'
						rowDatas[rowDatasLen]=strlen(value);
						rowDatasLen+=1;
						memcpy(rowDatas+rowDatasLen, value, strlen(value));
						rowDatasLen=rowDatasLen+strlen(value);
						break;
					case UPPER_STRING_S:	//'S'
						biglen=strlen(value);
						memcpy(rowDatas+rowDatasLen, &biglen, 2);
						rowDatasLen+=2;
						memcpy(rowDatas+rowDatasLen, value, strlen(value));
						rowDatasLen=rowDatasLen+strlen(value);
						break;
					case LOWER_STRING_B:	//'b'
						{
							int baselen;
							char base64buf[ROW_DATA_LEN]={0};
							memcpy(base64buf, value, strlen(value));
							//baselen=StringDecode(base64buf, rowDatas+rowDatasLen+1);
							baselen=StringDecode(rowDatas+rowDatasLen+1, base64buf);
							rowDatas[rowDatasLen]=baselen;
							rowDatasLen+=baselen+1;
							break;
						}
					case UPPER_STRING_B:	//'B'
						{
							int baselen;
							char base64buf[ROW_DATA_LEN]={0};
							memcpy(base64buf, value, strlen(value));
							//baselen=StringDecode(base64buf, rowDatas+rowDatasLen+2);
							baselen=StringDecode(rowDatas+rowDatasLen+2,base64buf);
							memcpy(rowDatas+rowDatasLen, &baselen, 2);
							rowDatasLen+=baselen+2;
							break;
						}
					default:
						break;
				}
			}
		}
		if (rowDatasLen>0)
			writeBufferAuto(buffer, rowDatas, rowDatasLen);
	}
	datalen=buffer->bufferSize-(buffer->bufEnd-buffer->bufPtr);
	sendlen=datalen;

	//保存字节流数据
	writebuffer((char*)buffer->buffer, datalen);
	cmd=CMD_DELETE_DATA;
	ret = COMMPULL_SENDCMDDATA(newCom->commpro , &cmd, rowDatas, &datalen, (char*)buffer->buffer, sendlen, newCom->timeoutMS);

	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
	
}

int UDK_API DeleteDeviceData(UDK_HANDLE Handle,
	const char *TableName,
	const char *Datas,
	const char *Options	
	)
{
    return PullSDKDeleteDeviceData(Handle, TableName, Datas, Options);
}



//查询设备信息，返回值为数据的长度
//For information equipment, the return value for the length of data
 int UDK_API PullSDKGetDeviceParam(
	UDK_HANDLE Handle, 
	char *Buffer,		//用于接收返回数据的缓冲区，返回的数据是文本格式的，如果返回的是多条信息，
						//各条信息之间用\r\n分隔，每条信息是一“信息项=值”对
						//To receive the data back to the buffer zone, the data is returned to the text, 
						//if the return is the number of information, Between all of the information 
						//used \ r \ n separated, each message is an "information = value "					
	int BufferSize,		//用于接收返回数据的缓冲区大小(For receiving data back to the size of the buffer zone)
	const char *Items	//要查询的设备信息项名称表，多个名称之间可以用逗号分开。当前可用的信息项参看附表
						//For the information of the name of the equipment table, 
						//a number of names can be used between the comma separated. Of the information currently available See Schedule
)
{
	char rowDatas[ROW_DATA_LEN] = {0};
	int sendlen=0, buflen=0, ret = 0;
	unsigned short cmd;

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) return ERROR_HANDLE;
	if(!Buffer) return ERR_BUFFER_NOT_ENOUGH;	
	cmd=CMD_GET_DEVICE_PARAM;
	sendlen=sprintf(Buffer, "%s", Items);
	buflen = BufferSize;
	ret = COMMPULL_SENDCMD2(newCom->commpro , &cmd, Buffer, &buflen, sendlen, newCom->timeoutMS, UDK_FALSE, NULL);
	return ret;
}

int UDK_API GetDeviceParam(
	UDK_HANDLE Handle, 
	char *Buffer,
	int BufferSize,	
	const char *Items
)
{
    return PullSDKGetDeviceParam(Handle, Buffer, BufferSize, Items);
}


//设置设备信息
 int UDK_API PullSDKSetDeviceParam(UDK_HANDLE Handle,
	const char *ItemAndValues	/*“信息项=值”对，多个项之间用\r\n分隔，例如
						System.PlayVoice="1.wav"	播放语音文件 1.wav
						Options.Baudrate=115200		设置232/485的通信波特率
						System.VideoFile=BASE64:xxx	上传宣传视频文件
						*/
)
{
	char rowDatas[ROW_DATA_LEN] = {0};
	int sendlen=0, buflen=0, ret = 0;
	unsigned short cmd;
	TNewCom *newCom=(TNewCom*)Handle;	
	if(!commobj_is_valid(newCom)) return ERROR_HANDLE;

	cmd=CMD_SET_DEVICE_PARAM;
	sendlen=sprintf(rowDatas, "%s", ItemAndValues);
	ret = COMMPULL_SENDCMD2(newCom->commpro , &cmd, rowDatas, &buflen, sendlen, newCom->timeoutMS, UDK_FALSE, NULL);
	return ret;
}

int UDK_API SetDeviceParam(UDK_HANDLE Handle, const char *ItemAndValues)
{
    return PullSDKSetDeviceParam(Handle, ItemAndValues);
}


int UDK_API PullSDKSearchDevice(char *CommType,char *Address, char *Buffer,int *BufferSize)
{
	char rowDatas[ROW_DATA_LEN] = {0};
	char sendbuf[128];
	int sendlen=0, buflen=0, ret=0;
	int cmd;
	
	PST_COMM_MODULE intf = find_comm_module_by_proto(CommType);
	if(intf){
		char* commlib = strdup(intf->comm_lib);
		//UDK_LOGD("use built-in commlib %s CommType:%s\n",commlib,CommType);
		if(!strcmp(CommType,"RS232") || !strcmp(CommType,"RS485") || !strcmp(CommType,"SerialPort")){
			cmd = CMD_BROADCAST;		
			ret=COMMPULL_COMSEARCH(commlib, Address , &cmd, NULL,0,Buffer,BufferSize, 3000);
		}else if(!strcmp(CommType,"UDP") || !strcmp(CommType,"Eth") || !strcmp(CommType,"Ethernet")){
			cmd = CMD_BROADCAST;
			sendlen = sprintf(sendbuf, "%s", "CallSecurityDevice");		
			ret=COMMPULL_BROADCAST(commlib, Address ,&cmd, sendbuf,sendlen,Buffer,BufferSize,3000);
		}
		udk_free(commlib);
	}else if(strcmp(CommType,"RS232")==0 || strcmp(CommType,"RS485")==0 || strcmp(CommType,"SerialPort")==0)
	{
		//串口设备需要考虑不同波特率，分别测试9600/19200/38400/57600/115200
		cmd = CMD_BROADCAST;
		buflen = ROW_DATA_LEN;
		ret=COMMPULL_COMSEARCH((char*)(UDK_RTLIBPREFIX COMMPRO_RS232 UDK_RTLIBSUFFIX), Address, &cmd, 				NULL,0,rowDatas, &buflen, 3000);
	}
	else if(strcmp(CommType,"UDP")==0 || strcmp(CommType,"Eth")==0 || strcmp(CommType,"Ethernet")==0)
	{
		cmd = CMD_BROADCAST;
		sendlen = sprintf(sendbuf, "%s", "CallSecurityDevice");		
		ret=COMMPULL_BROADCAST((char*)(UDK_RTLIBPREFIX COMMPRO_UDP_LIB UDK_RTLIBSUFFIX), Address , &cmd, 			sendbuf, sendlen,Buffer,BufferSize, 3000);
		
	}

	return ret;
}

int UDK_API SearchDevice(char *CommType,char *Address, 
                                    char *Buffer,int *BufferSize)
{
    return PullSDKSearchDevice(CommType, Address, Buffer, BufferSize);
}



//搜索设备，返回设备数量
 int UDK_API PullSDKModifyIPAddress(char *CommType, const char *Address, char *Buffer,int BufferSize)
{
	char rowDatas[ROW_DATA_LEN] = {0};
	int sendlen=0, buflen=0, ret=0;
	int cmd;
	buflen = BufferSize?BufferSize:strlen(Buffer);
	PST_COMM_MODULE intf = find_comm_module_by_proto(CommType);
	if(intf){
		char* commlib = strdup(intf->comm_lib);
		cmd = CMD_BROAD_MODIYIP;
		//COMMPULL_COMSEARCH(commlib, Address, &cmd,NULL,0,rowDatas, &buflen, 3000);
        ret=COMMPULL_BROADCAST(commlib, Address , &cmd, NULL,0,Buffer, &buflen, 3000);
		udk_free(commlib);		
	}else if(strcmp(CommType,"RS232")==0 || strcmp(CommType,"RS485")==0 || strcmp(CommType,"SerialPort")==0)
	{
		//串口设备需要考虑不同波特率，分别测试9600/19200/38400/57600/115200
		cmd = CMD_BROAD_MODIYIP;
		ret=COMMPULL_COMSEARCH((char*)(UDK_RTLIBPREFIX COMMPRO_RS232 UDK_RTLIBSUFFIX), Address, &cmd, NULL,0,rowDatas, &buflen, 3000);
	}else if(strcmp(CommType,"UDP")==0 || strcmp(CommType,"Eth")==0 || strcmp(CommType,"Ethernet")==0)
	{
		cmd = CMD_BROAD_MODIYIP;
		ret=COMMPULL_BROADCAST((char*)(UDK_RTLIBPREFIX COMMPRO_UDP_LIB UDK_RTLIBSUFFIX), Address , &cmd, NULL,0,Buffer, &buflen, 3000);
	}

	return ret;
}

int UDK_API ModifyIPAddress(char *CommType, const char *Address, 
                                    char *Buffer,int BufferSize)
{
    return PullSDKModifyIPAddress(CommType, Address, Buffer, BufferSize);
}

 int UDK_API PullSDKLastError()
{
	if (plLastError)
	{
		return plLastError;
	}
	return COMMPULL_LASTERROR();
}

int UDK_API LastError()
{
    return PullSDKLastError();
}

int UDK_API PullSDKBase64WriteToBMP(const char *base64, const char *fileBmp)
{
	int flen = 0;
	char *bin = NULL;
	char *p = NULL;
	int width = 0;
	int height = 0;

	//解出宽、高
	p = (char*)strstr(base64, "Width:");
	if(p)
	{
		width = atoi(p + strlen("Width:"));	//得到：Width:192,Height:388,Image:QAsoopustrAAAAoooo.....（Base64 编码）
							//中的：	  ↑ 并变换成数值
	}

	p = (char*)strstr(base64, "Height:");
	if(p)
	{
		height = atoi(p + strlen("Height:"));//得到：Width:192,Height:388,Image:QAsoopustrAAAAoooo.....（Base64 编码）
													//中的：	          ↑ 并变换成数值
	}

	if(width ==0 || height ==0) 
	{
		return ERROR_FORMAT_DATE;
	}

	p = (char*)strstr(base64, "Image:");
	if(!p)
	{
		return ERROR_FORMAT_DATE;
	}
	else
	{
		p = p + strlen("Image:");
	}

	bin = (char *)udk_malloc(strlen(base64)+1);//缓冲区bin，准备放解码后的数据
	if(bin == NULL) 
	{
		return ERROR_NO_MEM;
	}
	memset(bin, 0x00, strlen(base64)+1);

	flen = base64_decode((unsigned char *)p, (unsigned char *)bin);//将base64编码还原为二进制数据

	write_bitmap((char*)fileBmp, (unsigned char*)bin, width, height);
	udk_free(bin);

	return 1;
}



//查询设备中的数据，返回数据的字符长度
 int UDK_API PullSDKGetDeviceFileData(UDK_HANDLE Handle,
	char *Buffer,		
	int *BufferSize,		
	const char *FileName,	
	const char *Options
	)
{
	TNewCom *newCom=(TNewCom*)Handle;
	unsigned short cmd;
	
	int ret =0,sendlen = 0;

	if(!commobj_is_valid(newCom)) return ERROR_HANDLE;
	if(!Buffer||0==*BufferSize) return ERR_BUFFER_NOT_ENOUGH;

	cmd = CMD_GET_BINARYDATA;

	Buffer[0] = strlen(FileName);	
	sendlen = (UDK_U8)Buffer[0] + 1;
	memcpy(Buffer+1,FileName,sendlen);
	// add by 20150915,增加对Options参数处理
	if((Options != NULL) && (strcmp(Options, "") != 0))
	{
		memcpy(Buffer + sendlen, Options, strlen(Options));
		sendlen += strlen(Options);	// 发送的数据长度
	}
	//*BufferSize = 0;

	ret = COMMPULL_READCMDDATA(newCom->commpro , &cmd, Buffer, BufferSize, sendlen, (newCom->timeoutMS)*5);
//	*BufferSize = buflen;

	return ret;
}

int UDK_API GetDeviceFileData(UDK_HANDLE Handle,
	char *Buffer,		
	int *BufferSize,		
	const char *FileName,	
	const char *Options
	)
{
    return PullSDKGetDeviceFileData(Handle, Buffer, 
                                BufferSize, FileName, Options);
}


//下载设备中的数据，返回数据的字符长度, PC->dev
 int UDK_API PullSDKSetDeviceFileData(UDK_HANDLE Handle,
	const char *FileName,
	char *Buffer,		
	int BufferSize,			
	const char *Options
	)
{
#define FREE_RESOURCE() \
	do{\
		if(buffer) freeBuffer(buffer);\
	}\
	while(0)

	TBuffer *buffer=createRamBuffer(DATA_BUFFER_SIZE);
	TNewCom *newCom=(TNewCom*)Handle;
	unsigned short cmd;
	char confirmBuf[256] = {0};
	int confirmBufLen = 0, ret =0,sendlen = 0;
	int buflen = DATA_BUFFER_SIZE;

	if(newCom == NULL)
	{
		return ERROR_HANDLE;
	}
	assert(Buffer != NULL);
	//最大内存限制

	cmd = CMD_SET_BINARYDATA;
	
	buffer->buffer[0] = strlen(FileName);
	memcpy(buffer->buffer + 1 ,FileName,strlen(FileName));
	memcpy(buffer->buffer + 1 + strlen(FileName), Buffer,BufferSize);
	sendlen = 1 + strlen(FileName) + BufferSize;

	confirmBuf[0] = cmd;
	confirmBuf[1] = strlen(FileName);	//table name;
	confirmBufLen = 1 + strlen(FileName);
	ret = COMMPULL_SENDCMDDATA(newCom->commpro , 
		&cmd, 
		(char*)buffer->buffer,
		&buflen,
		(char*)buffer->buffer,
		sendlen, 
		(newCom->timeoutMS)*5);
	FREE_RESOURCE();
	return ret;
#undef FREE_RESOURCE
	
}

int UDK_API SetDeviceFileData(UDK_HANDLE Handle,
	const char *FileName,
	char *Buffer,		
	int BufferSize,			
	const char *Options
	)
{
    return PullSDKSetDeviceFileData(Handle, FileName, 
                                    Buffer, BufferSize, Options);
}

int UDK_API PullSDKSetAppid(void *Handle, const char *devid)
{
    unsigned short cmd = CMD_SET_APPID;
    int sendlen = 0;
    char buffer[10] = {0};   /* store devid string */

	TNewCom *newCom=(TNewCom*)Handle;
	if(!commobj_is_valid(newCom)) 
        return ERROR_HANDLE;
    if (!devid || *devid == '\0')
        return ERR_CMD_DATA_PARA_ERROR;

    memcpy(buffer, devid, strlen(devid));
    sendlen = strlen(devid);

	return COMMPULL_SENDCMD2(newCom->commpro, &cmd, buffer, &sendlen, sendlen, newCom->timeoutMS, UDK_FALSE, NULL);
}

int UDK_API PullSDKMobileAtt(UDK_HANDLE h, int operate, char *premeters, char *Buffer,int* BufferLength)
{
	return ERR_NOT_SUPPORT;
}

int UDK_API PullSDKSetDownloadProcessCallBack(UDK_HANDLE h, void *pCallBackFun)
{
	return ERR_NOT_SUPPORT;
}

int UDK_API PullSDKResetDeviceExt(UDK_HANDLE h, char *parameters)
{
	return ERR_NOT_SUPPORT;
}


